import { errorCode } from '@/constant/dict';
import { REGULAR_RULES } from '@/constant/regularRules';

/* 计算广播地址和网络号 */
export function getCIDR(ipAddress, subnetMask) {
    // 将IP地址和子网掩码转换为整数数组
    const ipParts = ipAddress.split('.').map(Number);
    const maskParts = subnetMask.split('.').map(Number);
    // 计算网络地址
    const networkAddress = ipParts
        .map(function (part, index) {
            return part & maskParts[index];
        })
        .join('.');
    // 计算广播地址
    const invertedMask = maskParts.map(function (part) {
        return 255 - part;
    });
    const broadcastAddress = ipParts
        .map(function (part, index) {
            return part | invertedMask[index];
        })
        .join('.');
    // 返回计算结果
    return {
        networkAddress,
        broadcastAddress
    };
}

/**
 *
 * @param {*} ipAddress 需要校验的ip地址（主要用在lanSetting，lanip的校验）
 * @param {*} subnetMask 子网掩码
 * @returns undefined or errorCode.EQUAL_NETWORK_ADDRESS error.EQUAL_BROAD_ADDRESS
 */
export function isEqualCIDR(ipAddress, subnetMask) {
    const { networkAddress, broadcastAddress } = getCIDR(ipAddress, subnetMask);
    if (networkAddress === ipAddress) {
        return errorCode.EQUAL_NETWORK_ADDRESS;
    }
    if (broadcastAddress === ipAddress) {
        return errorCode.EQUAL_BROAD_ADDRESS;
    }
}

const _ipToInteger = Symbol('ipToInteger');
const _integerToIp = Symbol('integerToIp');
const _getNetworkAddress = Symbol('getNetworkAddress');
export class IPNetworkSegment {
    /**
     * 校验两个IP是否在同一网段
     * @param {Array<String>} ipArr IP 数组
     * @param {String} subnetMask 子网掩码
     */
    constructor(ipArr, subnetMask) {
        // 传参错误
        if (!ipArr || ipArr.length !== 2 || !Array.isArray(ipArr)) {
            throw new Error('ipNetSegment function: parameter error');
        }

        const [mainIp, assistantIP] = ipArr;

        // IP格式错误
        if (!REGULAR_RULES.IPV4.test(mainIp) || !REGULAR_RULES.IPV4.test(assistantIP)) {
            throw new Error('ipNetSegment function: IP format error');
        }

        // MASK格式错误
        if (!REGULAR_RULES.MASK.test(subnetMask)) {
            throw new Error('ipNetSegment function: MASK format error');
        }

        this.mainIp = mainIp;
        this.assistantIP = assistantIP;
        this.subnetMask = subnetMask;
    }

    /**
     * 辅助函数：将IP地址转换为32位整数
     * @param {String} ipAddress
     * @returns
     */
    [_ipToInteger](ipAddress) {
        const ipArr = ipAddress.split('.');
        const ipInt = (parseInt(ipArr[0]) << 24) | (parseInt(ipArr[1]) << 16) | (parseInt(ipArr[2]) << 8) | parseInt(ipArr[3]);
        return ipInt;
    }

    /**
     * 辅助函数：将32位整数转换为IP地址
     * @param {String} ipInt
     * @returns
     */
    [_integerToIp](ipInt) {
        const byte1 = (ipInt >>> 24) & 0xff;
        const byte2 = (ipInt >>> 16) & 0xff;
        const byte3 = (ipInt >>> 8) & 0xff;
        const byte4 = ipInt & 0xff;
        const ipAddress = byte1 + '.' + byte2 + '.' + byte3 + '.' + byte4;
        return ipAddress;
    }

    /**
     * 将 IP 与 MASK 进行与位比较
     * @param {String} ipAddress
     * @param {String} subnetMask
     * @returns
     */
    [_getNetworkAddress](ipAddress, subnetMask) {
        const ipInt = this[_ipToInteger](ipAddress);
        const maskInt = this[_ipToInteger](subnetMask);
        const networkInt = ipInt & maskInt;
        const networkAddress = this[_integerToIp](networkInt);
        return networkAddress;
    }

    calculateNetworkSegment() {
        const mainIpAndMask = this[_getNetworkAddress](this.mainIp, this.subnetMask);
        const assistantIPAndMask = this[_getNetworkAddress](this.assistantIP, this.subnetMask);
        return String(mainIpAndMask) == String(assistantIPAndMask);
    }
}

/**
 * 判断是否 IPV4
 * @param {*} x
 * @returns
 */
export const parseIPv4 = (x) => {
    if (!x.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)) return null;

    if (RegExp.$1 > 255 || RegExp.$2 > 255 || RegExp.$3 > 255 || RegExp.$4 > 255) return null;

    return [+RegExp.$1, +RegExp.$2, +RegExp.$3, +RegExp.$4];
};

/**
 * 判断是否 IPV6
 * @param {String} x
 * @returns
 */
export const parseIPv6 = (x) => {
    const IPV6 = REGULAR_RULES.IPV6.test(x);

    if (!IPV6) {
        if (x.match(/^([a-fA-F0-9:]+):(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/)) {
            const v6 = RegExp.$1,
                v4 = parseIPv4(RegExp.$2);

            if (!v4) return null;

            x = v6 + ':' + (v4[0] * 256 + v4[1]).toString(16) + ':' + (v4[2] * 256 + v4[3]).toString(16);
        }

        if (!x.match(/^[a-fA-F0-9:]+$/)) return null;

        const prefix_suffix = x.split(/::/);

        if (prefix_suffix.length > 2) return null;

        const prefix = (prefix_suffix[0] || '0').split(/:/);
        const suffix = prefix_suffix.length > 1 ? (prefix_suffix[1] || '0').split(/:/) : [];

        if (suffix.length ? prefix.length + suffix.length > 7 : (prefix_suffix.length < 2 && prefix.length < 8) || prefix.length > 8) return null;

        let i, word;
        const words = [];

        for (i = 0, word = parseInt(prefix[0], 16); i < prefix.length; word = parseInt(prefix[++i], 16))
            if (prefix[i].length <= 4 && !isNaN(word) && word <= 0xffff) words.push(word);
            else return null;

        for (i = 0; i < 8 - prefix.length - suffix.length; i++) words.push(0);

        for (i = 0, word = parseInt(suffix[0], 16); i < suffix.length; word = parseInt(suffix[++i], 16))
            if (suffix[i].length <= 4 && !isNaN(word) && word <= 0xffff) words.push(word);
            else return null;

        return words;
    } else {
        return true;
    }
};

/**
 * 标准 IPV4/IPV6 校验(多个)，同时校验，示例：2001:db8::/32,110.220.39.103/2
 * @param {*} ip
 */
export const IPV46MultiMask = (ip) => {
    // 校验通过数组
    let correctArray = [];

    // 校验出错数组
    let wrongArray = [];

    if (ip) {
        const ipArr = String(ip).split(',');

        if (ipArr.includes('')) {
            wrongArray.push(ipArr);
        }

        for (const item of ipArr) {
            // 前缀格式错误
            if (item.split('/').length >= 3) {
                wrongArray.push(item);
            }

            const [ipAddress, subnetMask] = item.split('/');

            if (ipAddress) {
                const isValidIPv4 = REGULAR_RULES.IPV4_NO_PORT.test(ipAddress);

                const isValidIPv6 = parseIPv6(ipAddress);

                // 不是 IPV4 且不是 IPV6
                if (!isValidIPv4 && !isValidIPv6) {
                    wrongArray.push(item);
                }

                // IPV4
                if (isValidIPv4) {
                    // 子码掩码存在时
                    if (subnetMask) {
                        if (isNaN(+subnetMask) || +subnetMask < 0 || +subnetMask > 32 || subnetMask.length > 2) {
                            wrongArray.push(item);
                        } else {
                            correctArray.push(item);
                        }
                    }
                    // 子网掩码不存在时
                    else {
                        if (item.includes('/')) {
                            wrongArray.push(item);
                        } else {
                            correctArray.push(item);
                        }
                    }
                }
                // IPV6
                else if (isValidIPv6) {
                    // 子码掩码存在时
                    if (subnetMask) {
                        if (isNaN(+subnetMask) || +subnetMask < 0 || +subnetMask > 128 || subnetMask.length > 3) {
                            wrongArray.push(item);
                        } else {
                            correctArray.push(item);
                        }
                    }
                    // 子网掩码不存在时
                    else {
                        if (item.includes('/')) {
                            wrongArray.push(item);
                        } else {
                            correctArray.push(item);
                        }
                    }
                }
            }
        }
    }

    return { correctArray, wrongArray };
};
